using Rogan.Utility.Common;
using Rogan.Utility.Extensions;
using Rogan.Data.Resources;
using System;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.Text;
namespace Rogan.Data
{
	public sealed class Database : ILogable
	{
		public static Database Default = new Database(ProviderFactory.Default);
		public event LogHandler OnLog;
		public string ConnectionString
		{
			get
			{
				return DbProvider.ConnectionString;
			}
		}
		public DbProviderFactory DbProviderFactory
		{
			get
			{
				return DbProvider.DbProviderFactory;
			}
		}
		public DbProvider DbProvider
		{
			get;
			private set;
		}
		public Database(DbProvider dbProvider)
		{
			DbProvider = dbProvider;
			Guard.Check(dbProvider != null, "Cannot construct DbProvider");
		}
		public void WriteLog(DbCommand command)
		{
			if (OnLog != null)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append(string.Format("{0}:\t{1}\t\r\n", command.CommandType, command.CommandText));
				if (command.Parameters != null && command.Parameters.Count > 0)
				{
					stringBuilder.Append("Parameters:\r\n");
					foreach (DbParameter dbParameter in command.Parameters)
					{
						stringBuilder.Append(string.Format("{0}[{2}] = {1}\r\n", dbParameter.ParameterName, dbParameter.Value, dbParameter.DbType));
					}
				}
				OnLog(stringBuilder.ToString());
			}
		}
		public void WriteLog(string logMsg)
		{
			if (OnLog != null)
			{
				OnLog(logMsg);
			}
		}
		private void PrepareCommand(DbCommand command, DbConnection connection)
		{
			Guard.Check(command != null, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"command"
			}));
			Guard.Check(connection != null, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"connection"
			}));
			command.Connection = connection;
			DbProvider.PrepareCommand(command);
		}
		private void PrepareCommand(DbCommand command, DbTransaction transaction)
		{
			Guard.Check(command != null, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"command"
			}));
			Guard.Check(transaction != null, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"transaction"
			}));
			PrepareCommand(command, transaction.Connection);
			command.Transaction = transaction;
		}
		internal DbCommand CreateCommandByCommandType(CommandType commandType, string commandText)
		{
			DbCommand dbCommand = DbProvider.DbProviderFactory.CreateCommand();
			dbCommand.CommandType = commandType;
			dbCommand.CommandText = commandText;
			return dbCommand;
		}
		private void DoLoadDataSet(DbCommand command, DataSet dataSet, string[] tableNames)
		{
			Guard.Check(tableNames != null && tableNames.Length > 0, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"tableNames"
			}));
			Guard.Check(dataSet != null, TextResource.CanNotBeNull.FormatWith(new object[]
			{
				"dataSet"
			}));
			using (DbDataAdapter dataAdapter = GetDataAdapter())
			{
				WriteLog(command);
				((IDbDataAdapter)dataAdapter).SelectCommand = command;
				string text = "Table";
				for (int i = 0; i < tableNames.Length; i++)
				{
					string sourceTable = (i == 0) ? text : (text + i);
					dataAdapter.TableMappings.Add(sourceTable, tableNames[i]);
				}
				dataAdapter.Fill(dataSet);
			}
		}
		private object DoExecuteScalar(DbCommand command)
		{
			WriteLog(command);
			return command.ExecuteScalar();
		}
		private int DoExecuteNonQuery(DbCommand command)
		{
			WriteLog(command);
			return command.ExecuteNonQuery();
		}
		private IDataReader DoExecuteReader(DbCommand command, CommandBehavior cmdBehavior)
		{
			WriteLog(command);
			return command.ExecuteReader(cmdBehavior);
		}
		private DbTransaction BeginTransaction(DbConnection connection)
		{
			return connection.BeginTransaction();
		}
		private IDbTransaction BeginTransaction(DbConnection connection, IsolationLevel il)
		{
			return connection.BeginTransaction(il);
		}
		private static void ConfigureParameter(DbParameter param, string name, DbType dbType, int size, ParameterDirection direction, bool nullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value)
		{
			param.DbType = dbType;
			param.Size = size;
			param.Value = ((value == null) ? DBNull.Value : value);
			param.Direction = direction;
			param.IsNullable = nullable;
			param.SourceColumn = sourceColumn;
			param.SourceVersion = sourceVersion;
		}
		private DbParameter CreateParameter(string name, DbType dbType, int size, ParameterDirection direction, bool nullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value)
		{
			DbParameter dbParameter = CreateParameter(name);
			ConfigureParameter(dbParameter, name, dbType, size, direction, nullable, precision, scale, sourceColumn, sourceVersion, value);
			return dbParameter;
		}
		private DbParameter CreateParameter(string name)
		{
			DbParameter dbParameter = DbProvider.DbProviderFactory.CreateParameter();
			dbParameter.ParameterName = DbProvider.BuildParameterName(name);
			return dbParameter;
		}
		public void CloseConnection(DbCommand command)
		{
			if (command != null && command.Connection.State != ConnectionState.Closed && command.Transaction == null)
			{
				CloseConnection(command.Connection);
				command.Dispose();
			}
		}
		public void CloseConnection(DbConnection conn)
		{
			if (conn != null && conn.State != ConnectionState.Closed)
			{
				try
				{
					conn.Close();
					conn.Dispose();
				}
				catch
				{
				}
			}
		}
		public void CloseConnection(DbTransaction tran)
		{
			if (tran.Connection != null)
			{
				CloseConnection(tran.Connection);
				tran.Dispose();
			}
		}
		public DbConnection GetConnection()
		{
			return CreateConnection();
		}
		public DbConnection GetConnection(bool tryOpen)
		{
			return CreateConnection(tryOpen);
		}
		public DbConnection CreateConnection()
		{
			DbConnection dbConnection = DbProvider.DbProviderFactory.CreateConnection();
			dbConnection.ConnectionString = ConnectionString;
			return dbConnection;
		}
		public DbConnection CreateConnection(bool tryOpenning)
		{
			if (!tryOpenning)
			{
				return CreateConnection();
			}
			DbConnection dbConnection = null;
			try
			{
				dbConnection = CreateConnection();
				dbConnection.Open();
			}
			catch
			{
				try
				{
					dbConnection.Close();
				}
				catch
				{
				}
				throw;
			}
			return dbConnection;
		}
		public DbCommand GetStoredProcCommand(string storedProcedureName)
		{
			Guard.IsNotNullOrEmpty(storedProcedureName, "storedProcedureName");
			return CreateCommandByCommandType(CommandType.StoredProcedure, storedProcedureName);
		}
		public DbCommand GetSqlStringCommand(string query)
		{
			Guard.IsNotNullOrEmpty(query, "query");
			return CreateCommandByCommandType(CommandType.Text, query);
		}
		public DbDataAdapter GetDataAdapter()
		{
			return DbProvider.DbProviderFactory.CreateDataAdapter();
		}
		public void LoadDataSet(DbTransaction transaction, CommandType commandType, string commandText, DataSet dataSet, string[] tableNames)
		{
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				LoadDataSet(dbCommand, dataSet, tableNames, transaction);
			}
		}
		public IDataReader ExecuteReader(CommandType commandType, string commandText)
		{
			IDataReader result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteReader(dbCommand);
			}
			return result;
		}
		public IDataReader ExecuteReader(DbTransaction transaction, CommandType commandType, string commandText)
		{
			IDataReader result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteReader(dbCommand, transaction);
			}
			return result;
		}
		public void LoadDataSet(DbCommand command, DataSet dataSet, string tableName)
		{
			LoadDataSet(command, dataSet, new[]
			{
				tableName
			});
		}
		public void LoadDataSet(DbCommand command, DataSet dataSet, string tableName, DbTransaction transaction)
		{
			LoadDataSet(command, dataSet, new[]
			{
				tableName
			}, transaction);
		}
		public void LoadDataSet(DbCommand command, DataSet dataSet, string[] tableNames)
		{
			using (DbConnection connection = GetConnection())
			{
				PrepareCommand(command, connection);
				DoLoadDataSet(command, dataSet, tableNames);
			}
		}
		public void LoadDataSet(DbCommand command, DataSet dataSet, string[] tableNames, DbTransaction transaction)
		{
			PrepareCommand(command, transaction);
			DoLoadDataSet(command, dataSet, tableNames);
		}
		public void LoadDataSet(CommandType commandType, string commandText, DataSet dataSet, string[] tableNames)
		{
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				LoadDataSet(dbCommand, dataSet, tableNames);
			}
		}
		public DataSet ExecuteDataSet(DbCommand command)
		{
			DataSet dataSet = new DataSet();
			dataSet.Locale = CultureInfo.InvariantCulture;
			LoadDataSet(command, dataSet, "Table");
			return dataSet;
		}
		public DataSet ExecuteDataSet(DbCommand command, DbTransaction transaction)
		{
			DataSet dataSet = new DataSet();
			dataSet.Locale = CultureInfo.InvariantCulture;
			LoadDataSet(command, dataSet, "Table", transaction);
			return dataSet;
		}
		public DataSet ExecuteDataSet(CommandType commandType, string commandText)
		{
			DataSet result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteDataSet(dbCommand);
			}
			return result;
		}
		public DataSet ExecuteDataSet(DbTransaction transaction, CommandType commandType, string commandText)
		{
			DataSet result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteDataSet(dbCommand, transaction);
			}
			return result;
		}
		public object ExecuteScalar(DbCommand command)
		{
			object result;
			using (DbConnection connection = GetConnection(true))
			{
				PrepareCommand(command, connection);
				result = DoExecuteScalar(command);
			}
			return result;
		}
		public object ExecuteScalar(DbCommand command, DbTransaction transaction)
		{
			PrepareCommand(command, transaction);
			return DoExecuteScalar(command);
		}
		public object ExecuteScalar(CommandType commandType, string commandText)
		{
			object result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteScalar(dbCommand);
			}
			return result;
		}
		public object ExecuteScalar(DbTransaction transaction, CommandType commandType, string commandText)
		{
			object result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteScalar(dbCommand, transaction);
			}
			return result;
		}
		public int ExecuteNonQuery(DbCommand command)
		{
			int result;
			using (DbConnection connection = GetConnection(true))
			{
				PrepareCommand(command, connection);
				result = DoExecuteNonQuery(command);
			}
			return result;
		}
		public int ExecuteNonQuery(DbCommand command, DbTransaction transaction)
		{
			PrepareCommand(command, transaction);
			return DoExecuteNonQuery(command);
		}
		public int ExecuteNonQuery(CommandType commandType, string commandText)
		{
			int result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteNonQuery(dbCommand);
			}
			return result;
		}
		public int ExecuteNonQuery(DbTransaction transaction, CommandType commandType, string commandText)
		{
			int result;
			using (DbCommand dbCommand = CreateCommandByCommandType(commandType, commandText))
			{
				result = ExecuteNonQuery(dbCommand, transaction);
			}
			return result;
		}
		public IDataReader ExecuteReader(DbCommand command)
		{
			DbConnection connection = GetConnection(true);
			PrepareCommand(command, connection);
			IDataReader result;
			try
			{
				result = DoExecuteReader(command, CommandBehavior.CloseConnection);
			}
			catch
			{
				try
				{
					connection.Close();
				}
				catch
				{
				}
				throw;
			}
			return result;
		}
		public IDataReader ExecuteReader(DbCommand command, DbTransaction transaction)
		{
			PrepareCommand(command, transaction);
			return DoExecuteReader(command, CommandBehavior.Default);
		}
		public DbTransaction BeginTransaction()
		{
			return GetConnection(true).BeginTransaction();
		}
		public DbTransaction BeginTransaction(IsolationLevel il)
		{
			return GetConnection(true).BeginTransaction(il);
		}
		public void AddParameter(DbCommand command, string name, DbType dbType, int size, ParameterDirection direction, bool nullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value)
		{
			DbParameter value2 = CreateParameter(name, (dbType == DbType.Object) ? DbType.String : dbType, size, direction, nullable, precision, scale, sourceColumn, sourceVersion, value);
			command.Parameters.Add(value2);
		}
		public void AddParameter(DbCommand command, string name, DbType dbType, ParameterDirection direction, string sourceColumn, DataRowVersion sourceVersion, object value)
		{
			AddParameter(command, name, dbType, 0, direction, false, 0, 0, sourceColumn, sourceVersion, value);
		}
		public void AddOutParameter(DbCommand command, string name, DbType dbType, int size)
		{
			AddParameter(command, name, dbType, size, ParameterDirection.Output, true, 0, 0, string.Empty, DataRowVersion.Default, DBNull.Value);
		}
		public void AddInParameter(DbCommand command, string name, DbType dbType)
		{
			AddParameter(command, name, dbType, ParameterDirection.Input, string.Empty, DataRowVersion.Default, null);
		}
		public void AddInParameter(DbCommand command, string name, DbType dbType, object value)
		{
			AddParameter(command, name, dbType, ParameterDirection.Input, string.Empty, DataRowVersion.Default, value);
		}
		public void AddInParameter(DbCommand command, string name, DbType dbType, int size, object value)
		{
			AddParameter(command, name, dbType, size, ParameterDirection.Input, true, 0, 0, string.Empty, DataRowVersion.Default, value);
		}
		public void AddInParameter(DbCommand command, string name, object value)
		{
			AddParameter(command, name, DbType.Object, ParameterDirection.Input, string.Empty, DataRowVersion.Default, value);
		}
		public void AddInParameter(DbCommand command, string name, DbType dbType, string sourceColumn, DataRowVersion sourceVersion)
		{
			AddParameter(command, name, dbType, 0, ParameterDirection.Input, true, 0, 0, sourceColumn, sourceVersion, null);
		}
		public void AddInputOutputParameter(DbCommand command, string name, DbType dbType, int size, object value)
		{
			AddParameter(command, name, dbType, size, ParameterDirection.InputOutput, true, 0, 0, string.Empty, DataRowVersion.Default, value);
		}
		public void AddReturnValueParameter(DbCommand command, string name, DbType dbType, int size)
		{
			AddParameter(command, name, dbType, size, ParameterDirection.ReturnValue, true, 0, 0, string.Empty, DataRowVersion.Default, DBNull.Value);
		}
		public void AddParameter(DbCommand command, params DbParameter[] parameters)
		{
			if (parameters == null || parameters.Length == 0)
			{
				return;
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				DbParameter dbParameter = parameters[i];
				dbParameter.ParameterName = DbProvider.BuildParameterName(dbParameter.ParameterName);
				command.Parameters.Add(dbParameter);
			}
		}
		internal DbCommand AddCommandParameter(DbCommand command, params QueryParameter[] parameters)
		{
			if (parameters == null || parameters.Length == 0)
			{
				return command;
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				QueryParameter queryParameter = parameters[i];
				DbParameter dbParameter = CreateParameter(queryParameter.Name);
				dbParameter.Value = queryParameter.Value;
				if (queryParameter.DbType.HasValue)
				{
					dbParameter.DbType = queryParameter.DbType.Value;
				}
				if (queryParameter.Size.HasValue)
				{
					dbParameter.Size = queryParameter.Size.Value;
				}
				command.Parameters.Add(dbParameter);
			}
			return command;
		}

        event LogHandler ILogable.OnLog
        {
            add { throw new NotImplementedException(); }
            remove { throw new NotImplementedException(); }
        }
    }
}
